/*
 * Copyright 2009 Prime Technology.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.primefaces.optimus.listener;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.wideplay.warp.persist.PersistenceService;
import com.wideplay.warp.persist.UnitOfWork;

import org.primefaces.optimus.auth.AuthContext;
import org.primefaces.optimus.config.CoreModule;
import org.primefaces.optimus.config.OptimusBeanContext;
import org.primefaces.optimus.persistence.JPAModule;
import org.primefaces.optimus.persistence.PersistenceManager;
import org.primefaces.optimus.util.Constants;

public class ContextListener implements ServletContextListener {
	
	private static final Logger logger = Logger.getLogger(ContextListener.class.getName());

	public void contextInitialized(ServletContextEvent servletContextEvent) {
		ServletContext context = servletContextEvent.getServletContext();
		
		initializeAuthContext(context);
		
		logger.info("Initializing Optimus Context");
		Injector injector = initializeInjector(context);
		
		initializeOptimusBeanContext(context, injector);
		
		if(isPersistenceEnabled(context)) {
			PersistenceManager persistenceManager = injector.getInstance(PersistenceManager.class);
			persistenceManager.configure();
			logger.info("Optimus JPA persistence support is enabled");
		} else {
			logger.info("Optimus JPA persistence support is disabled");
		}

		logger.info("Optimus Context initialized successfully");
	}

	public void contextDestroyed(ServletContextEvent servletContextEvent) {
		//TODO: Clear stuff
	}
	
	private void initializeOptimusBeanContext(ServletContext servletContext, Injector injector) {
		OptimusBeanContext optimusBeanContext = injector.getInstance(OptimusBeanContext.class);
		optimusBeanContext.initialize(servletContext, injector);
		
		servletContext.setAttribute(Constants.BEANCONTEXT_KEY, optimusBeanContext);
	}
	
	private Injector initializeInjector(ServletContext servletContext) {
		List<Module> modules = new ArrayList<Module>();
		modules.add(new CoreModule());
		
		String modulesInitParameter = servletContext.getInitParameter(Constants.CONFIG_MODULES);
		
		if(modulesInitParameter != null) {
			String[] moduleNames = modulesInitParameter.split(",");
			
			for(String moduleName : moduleNames) {
				String trimmedModuleName = moduleName.trim();
				
				try {
					Module module = (Module) Class.forName(trimmedModuleName).newInstance();
					
					modules.add(module);
				} catch (Exception e) {
					logger.severe(e.getMessage());
					
					throw new RuntimeException(e);
				}
			}
		}
	
		if(isPersistenceEnabled(servletContext)) {
			modules.add(new JPAModule(servletContext.getInitParameter(Constants.PERSISTENCE_UNIT)));
			modules.add(PersistenceService.usingJpa().across(UnitOfWork.REQUEST).buildModule());
		}
		
		Injector injector = Guice.createInjector(modules);
		
		servletContext.setAttribute(Constants.INJECTOR_KEY, injector);
		
		return injector;
	}
	
	private boolean isPersistenceEnabled(ServletContext servletContext) {
		return servletContext.getInitParameter(Constants.PERSISTENCE_UNIT) != null;
	}
	
	private void initializeAuthContext(ServletContext context) {
		AuthContext authContextImpl = null;
		String authContextImplAsString = context.getInitParameter(Constants.AUTH_CONTEXT_IMPL);
		
		try {
			if(authContextImplAsString != null)
				authContextImpl = (AuthContext) Class.forName(authContextImplAsString).newInstance();
			else
				authContextImpl = (AuthContext) Class.forName("org.primefaces.optimus.auth.AuthContextImpl").newInstance();	
				
		} catch (Exception e) {
			e.printStackTrace();	//TODO: Log error
		}

		context.setAttribute(Constants.AUTHCONTEXT_KEY, authContextImpl);
	}
}